#include "stdafx.h"
#include "ui_gdi_render_util.h"
#include "ui_offset_dc.h"

_SSL_BEGIN
_SSUIL_BEGIN

void UIGdiRenderUtil::DrawColor(HDC dc, const UIRect &dest_rt, unsigned long color)
{
	DWORD alpha_value = 0;
	color = DWORDStripAlpha(color, alpha_value);

	if(alpha_value == 0xff)
	{
		DrawColorInternal(dc, dest_rt, color);
		return;
	}

	UIOffScreenDC alpha_dc;

	HDC dc_alpha_h = AlphaDrawPre(alpha_dc, dest_rt, dc);

	UIRect rt_alpha(0, 0, dest_rt.Width(), dest_rt.Height());

	DrawColorInternal(dc_alpha_h, rt_alpha, color);

	AlphaDrawPost(alpha_dc, dest_rt, dc, alpha_value);
}

void UIGdiRenderUtil::DrawFrame(HDC dc, const UIRect &dest_rt, unsigned long color)
{
	DWORD alpha_value = 0;
	color = DWORDStripAlpha(color, alpha_value);

	if(dest_rt.IsEmptry())
		return;
	if(alpha_value == 0xff)
	{
		return DrawFrameInternal(dc, dest_rt, color);
	}

	UIOffScreenDC alpha_dc;

	HDC dc_alpha_h = AlphaDrawPre(alpha_dc, dest_rt, dc);

	UIRect rt_alpha(0, 0, dest_rt.Width(), dest_rt.Height());

	DrawFrameInternal(dc_alpha_h, rt_alpha, color);

	AlphaDrawPost(alpha_dc, dest_rt, dc, alpha_value);
}

void UIGdiRenderUtil::DrawText(HDC dc, const tchar *text, int text_len,
	unsigned long text_color, const UIRect *rt, HFONT font, unsigned int style,
	bool transparent, unsigned long bk_color /*= 0*/)
{
	DWORD alpha_value = 0;
	text_color = DWORDStripAlpha(text_color, alpha_value);

	if(alpha_value == 0xff)
	{
		DrawTextInternal(dc, text, text_len, text_color, rt, font, style, transparent, bk_color);
		return;
	}

	if(rt == NULL)
	{
		return;
	}
	UIOffScreenDC alpha_dc;

	HDC dc_alpha_h = AlphaDrawPre(alpha_dc, *rt, dc);

	UIRect rt_alpha(0, 0, rt->Width(), rt->Height());
	DrawTextInternal(dc_alpha_h, text, text_len, text_color, &rt_alpha, font, style, transparent, bk_color);

	AlphaDrawPost(alpha_dc, *rt, dc, alpha_value);
}

bool UIGdiRenderUtil::MeasureTextSize(const tchar *text, int text_len,
	ss_inout_ UIRect &rt, HFONT font, UIMeasureTextType measure_type)
{
#define kMaxCanvasLength 4096
	UIRect rt_canvas(rt);
	unsigned int style = DT_CALCRECT|DT_EDITCONTROL|DT_WORDBREAK;
	switch(measure_type)
	{
	case kMeasureWidthAndHeight:
		rt_canvas.right = rt_canvas.left + kMaxCanvasLength;
		style |= DT_SINGLELINE;
	case kMeasureHeight:
		if(rt_canvas.Width() <= 0)
			return false;
		rt_canvas.bottom = rt_canvas.top + kMaxCanvasLength;
		break;
	default:
		return false;
	}

	HDC dc_handle = ::GetDC(NULL);
	int dc_saved = ::SaveDC(dc_handle);

	::SelectObject(dc_handle, font);

	::DrawText(dc_handle, text, text_len, &rt_canvas, style);
	rt = rt_canvas;

	::RestoreDC(dc_handle, dc_saved);
	dc_saved = 0;
	::ReleaseDC(NULL, dc_handle);
	dc_handle = NULL;

	return true;
}

HDC UIGdiRenderUtil::AlphaDrawPre(UIOffScreenDC &dc, const UIRect &rt, HDC dc_ori)
{
	dc.Init(GetDesktopWindow(), &rt);

	HDC dc_h = dc.GetDC();

	HBITMAP dst_bm_h = (HBITMAP)GetCurrentObject(dc_ori, OBJ_BITMAP);
	BITMAP dst_bm = {0};
	::GetObject(dst_bm_h, sizeof(dst_bm), &dst_bm);
	BYTE *dst = (BYTE*)dst_bm.bmBits;

	HBITMAP bm_h = dc.GetMemBitmap();
	BITMAP bm = {0};
	::GetObject(bm_h, sizeof(bm), &bm);
	BYTE *source = (BYTE*)bm.bmBits;
	LONG lH = bm.bmHeight;
	if(rt.bottom > dst_bm.bmHeight)
		lH = dst_bm.bmHeight - rt.top;
	SS_ASSERT(dst_bm.bmBitsPixel >= 24);
	int oy = 0, ox = 0;;
	if(rt.top < 0)
		oy = -rt.top;
	if(rt.left < 0)
		ox = -rt.left;

	for(int y=oy; y<lH; y++)
	{
		for(int x=ox; x<bm.bmWidth; x++)
		{
			byte *s_p = source + (bm.bmHeight - y - 1) * bm.bmWidthBytes + x * 4;
			byte *d_p = dst + (dst_bm.bmHeight - rt.top - y - 1) * dst_bm.bmWidthBytes + (rt.left + x) * (dst_bm.bmBitsPixel/8);
			s_p[0] = d_p[0];
			s_p[1] = d_p[1];
			s_p[2] = d_p[2];
			s_p[3] = 0xee;
		}
	}
	return dc_h;
}

void UIGdiRenderUtil::AlphaDrawPost(UIOffScreenDC &dc, const UIRect &rt, HDC dc_h, int alpha_value)
{
	HBITMAP dst_bm_h = (HBITMAP)GetCurrentObject(dc_h, OBJ_BITMAP);
	BITMAP dst_bm = {0};
	::GetObject(dst_bm_h, sizeof(dst_bm), &dst_bm);
	BYTE *dst = (BYTE*)dst_bm.bmBits;

	HBITMAP bm_h = dc.GetMemBitmap();
	BITMAP bm = {0};
	::GetObject(bm_h, sizeof(bm), &bm);
	BYTE *source = (BYTE*)bm.bmBits;
	LONG lH = bm.bmHeight;
	if(rt.bottom > dst_bm.bmHeight)
		lH = dst_bm.bmHeight - rt.top;
	float alhpa = (float)alpha_value / 255;

	int oy = 0, ox = 0;;
	if(rt.top < 0)
		oy = -rt.top;
	if(rt.left < 0)
		ox = -rt.left;

	UIRect rt_clipbox;

	GetClipBox(dc_h, &rt_clipbox);
	rt_clipbox.left -= rt.left;
	rt_clipbox.right -= rt.left;
	rt_clipbox.top -= rt.top;
	rt_clipbox.bottom -= rt.top;

	for(int y=oy; y<lH; y++)
	{
		for(int x=ox; x<bm.bmWidth; x++)
		{
			POINT pt;
			pt.x = x;
			pt.y = y;
			if(!::PtInRect(&rt_clipbox, pt))
			{
				continue;
			}
			byte *s_p = source + (bm.bmHeight - y - 1) * bm.bmWidthBytes + x * 4;
			byte *d_p = dst + (dst_bm.bmHeight - rt.top - y - 1) * dst_bm.bmWidthBytes + (rt.left + x) * (dst_bm.bmBitsPixel/8);
			if(s_p[3] != 0xee)
			{
				d_p[0] = (byte)(s_p[0] * alhpa) + (byte)(d_p[0] * (1- alhpa));
				d_p[1] = (byte)(s_p[1] * alhpa) + (byte)(d_p[1] * (1- alhpa));
				d_p[2] = (byte)(s_p[2] * alhpa) + (byte)(d_p[2] * (1- alhpa));
			}
		}
	}
}

void UIGdiRenderUtil::DrawTextInternal(HDC dc, const tchar *text, int text_len,
	unsigned long text_color, const UIRect *rt, HFONT font, unsigned int style,
	bool transparent, unsigned long bk_color /*= 0*/)
{
	if(::GetObjectType(dc) != OBJ_DC && ::GetObjectType(dc) != OBJ_MEMDC)
		return;
	if(font == NULL)
		return;

	int dc_snap = ::SaveDC(dc);

	::SelectObject(dc, font);

	UIRect rt_l;
	if(rt != NULL)
	{
		rt_l = *rt;
	}

	unsigned int dt_style = DT_EDITCONTROL|DT_WORDBREAK;
	if(SS_FLAG_ISSET(style, kTextStyleLeft))
		dt_style |= DT_LEFT;
	if(SS_FLAG_ISSET(style, kTextStyleCenter))
		dt_style |= DT_CENTER;
	if(SS_FLAG_ISSET(style, kTextStyleRight))
		dt_style |= DT_RIGHT;
	if(SS_FLAG_ISSET(style, kTextStyleTop))
		dt_style |= DT_TOP;
	if(SS_FLAG_ISSET(style, kTextStyleVCenter))
		dt_style |= DT_VCENTER;
	if(SS_FLAG_ISSET(style, kTextStyleBottom))
		dt_style |= DT_BOTTOM;
	if(SS_FLAG_ISSET(style, kTextStyleSingleLine))
		dt_style |= DT_SINGLELINE;
	::SetBkMode(dc, transparent ? TRANSPARENT : OPAQUE);
	::SetBkColor(dc, DWORD2RGB(bk_color));
	::SetTextColor(dc, DWORD2RGB(text_color));
	::DrawText(dc, text, text_len, &rt_l, dt_style);

	::RestoreDC(dc, dc_snap);
}

void UIGdiRenderUtil::DrawColorInternal(HDC dc, const UIRect &dest_rt, unsigned long color)
{
	if(::GetObjectType(dc) != OBJ_DC && ::GetObjectType(dc) != OBJ_MEMDC)
		return;

	HDC dc_handle = (HDC)dc;
	COLORREF old_bk_color = ::GetBkColor(dc_handle);
	::SetBkColor(dc_handle, DWORD2RGB(color));
	::ExtTextOut(dc_handle, 0, 0, ETO_OPAQUE, &dest_rt, NULL, 0, NULL);
	::SetBkColor(dc_handle, old_bk_color);
}

void UIGdiRenderUtil::DrawFrameInternal(HDC dc, const UIRect &dest_rt, unsigned long color)
{
	if(::GetObjectType(dc) != OBJ_DC && ::GetObjectType(dc) != OBJ_MEMDC)
		return;

	HBRUSH brs = ::CreateSolidBrush(DWORD2RGB(color));
	::FrameRect((HDC)dc, &dest_rt, brs);
	::DeleteObject(brs);
}

_SSUIL_END
_SSL_END

